class Entity < ActiveRecord::Base	
	#is friends relationship
	has_many :friendships, :dependent => :destroy
	has_many :friends, :through => :friendships	

	#can author many public and private popsicles
	has_many :public_messages, :class_name => 'PublicPopsicle', :foreign_key => 'public_author_id'
	has_many :private_messages, :class_name => 'PrivatePopsicle', :foreign_key => 'private_author_id'
  
  #can host many public messages
  has_many :message_tenants, :class_name => 'PublicPopsicle', :foreign_key => 'created_location_id' 
	
	#can receive many private popsicles
	has_many :receive_messages, :class_name => 'ReceiveMessage'
	has_many :private_messages_received, :through => :receive_messages, :source => :message
	
	#part of puddle relationship
	has_many :puddleships, :dependent => :destroy
	has_many :containingPuddles, :class_name => 'Puddle', :through => :puddleships
	#edits puddle relationship
	has_many :puddles, :dependent => :destroy
  
  has_one :privacy_level, :class_name => 'Privacy', :dependent => :destroy
   
  
  has_attached_file :audio_welcome
  validates_attachment_content_type :audio_welcome, :content_type => ['audio/mp3', 'audio/wav', 'audio/ogg']
	  
	validates :name, :presence => true
	validates :type, :presence => true
	
	before_destroy :validate_destruction
	after_create :set_default_privacy
  after_create :create_all_friends_puddle

	before_post_process :sanitise_filename

   
  #---------------------------------------- Validation methods
  
  def create_all_friends_puddle #Created by Adrian
    self.create_puddle("All Friends")
  end
  
  def sanitise_filename  #Created by Adrian
   
    basename = File.basename(audio_welcome.url) 
    if /\.mp3/ =~ basename
      extension = ".mp3"
    elsif /\.wav/ =~ basename
      extension = ".wav"
    elsif /\.ogg/ =~ basename
      extension = ".ogg"
    else
      extension = ".png"
    end
    puts basename.gsub!(/[\%20|?.*]/,'')
    self.audio_welcome.instance_write(:url,basename + extension)
  end
  
    # use this method to control whether or not an entity may be destroyed
  def validate_destruction #Michael
    destroy_valid = true
    
    Administrate.find_all_by_entity_id(self.id).each do |ar|
      if Group.find(ar.group_id).admins.count < 2
        destroy_valid = false
      end
    end    
    destroy_valid
  end
  
  
  # use this method to set the default privacy level before saving into the db
  def set_default_privacy #Created by Adrian      
    if self.privacy_level.nil?
      puts "creating privacy for " + self.id.to_s  
      puts Privacy.create(:entity_id => self.id)
    end
  end
  
	#---------------------------------------- these methods relate to this entities friends
  
  def friends #Created by Adrian 
    @friends = []   
    Friendship.find(:all, :conditions => {:friend_id => self.id, :accepted => true}).each do |f|
            if(User.exists?(f.entity_id))
        @friends << User.find(f.entity_id)
      end
    end
    Friendship.find(:all, :conditions => {:entity_id => self.id, :accepted => true}).each do |f|
      if(User.exists?(f.friend_id))
        @friends << User.find(f.friend_id)
      end
    end
    return @friends
  end
 
	#returns all friends with a privacy level lower than 4
	def find_permissible_friends #Created by Adrian
		permissible_friends = []
		self.friends.each do |f|		
			if f.privacy_level.private_messaging < 3
				permissible_friends << f
			end
		end
		return permissible_friends
	end
	
	def find_groups #Created by Ethan
		entities = []		
		Friendship.find(:all, :conditions => {:friend_id => self.id, :accepted => true}).each do |f|
			if(Group.exists?(f.entity_id))
				entities << Group.find(f.entity_id)
			end
		end
		Friendship.find(:all, :conditions => {:entity_id => self.id, :accepted => true}).each do |f|
			if(Group.exists?(f.friend_id))
				entities << Group.find(f.friend_id)
			end
		end
		return entities
	end
	
	def friends_stream #Created by Adrian	
		messages = []
		self.friends.each do |f|		
			if !PublicPopsicle.find_by_public_author_id(f.id).nil?
				PublicPopsicle.find(:all, :conditions => {:public_author_id => f.id, :prev_popsicle => nil }).each do |m|
					messages << m
				end
			end
		end
		return messages
  end

  def introverted_stream #Created by Adrian 
    messages = []
    self.friends.each do |f|    
      if !PublicPopsicle.find_by_public_author_id(f.id).nil?
        PublicPopsicle.find(:all, :conditions => {:public_author_id => f.id, :prev_popsicle => nil, :created_location_id => self.id}).each do |m|
          messages << m
        end
      end
    end
    return messages
  end
  
  def extraverted_stream #Created by Adrian 
    messages = []
    self.friends.each do |f|    
      if !PublicPopsicle.find_by_public_author_id(f.id).nil?
        PublicPopsicle.find(:all, :conditions => {:public_author_id => f.id, :prev_popsicle => nil}).each do |m|
          group = Group.exists?(m.created_location_id) ? Group.find(m.created_location_id) : nil
          if group.nil? || !group.introverted
            messages << m
          end
        end
      end
    end
    return messages
  end

  #---------------------------------------- privacy methods - Adrian
  
  def can_be_searched(entity) #Created by Adrian
    privacy_level = self.privacy_level.search
    return (self.friends.include?entity) || 
           (entity.is_friend_of_friend(self) && privacy_level < 3) ||
           (privacy_level == 0)    
  end
  
  def can_be_sent_friend_request(entity) #Created by Adrian
    privacy_level = self.privacy_level.requests
    return ((privacy_level < 3) && 
           ((entity.is_friend_of_friend(self)) || (privacy_level == 0)))
  end

  def can_be_sent_private_message(entity) #Created by Adrian
    privacy_level = self.privacy_level.private_messaging
    return (privacy_level < 3) &&
           ((self.friends.include?entity) || 
           (entity.is_friend_of_friend(self) && privacy_level < 2) ||
           (privacy_level == 0))
  end
  
  def can_have_stream_seen_by(entity) #Created by Adrian
    privacy_level = self.privacy_level.stream_view
    return (entity == self) ||
           ((privacy_level < 3) &&
           ((self.friends.include?entity) || 
           (entity.is_friend_of_friend(self) && privacy_level < 3) ||
           (privacy_level == 0)))
  end

	#---------------------------------------- this method ensures correct set up of a new group
	def create_group(name, description, introverted) # Michael
		group = Group.create(:name => name, :description => description, :introverted => introverted)
		group.initialise_relationships(self.id)
		group
	end
	
	#---------------------------------------- these methods for manipulating puddles
	def create_puddle(name)#Ethan
		Puddle.create(:name => name, :entity_id => self.id)
	end
	
	def delete_puddle(puddle)#Ethan
		puddle.delete
	end

	def find_puddles#Ethan
		puddles = []
		Puddle.find(:all, :conditions=>{:entity_id => self.id}).each do |p|
			puddles << p
		end
		return puddles
	end
	
  
  #Adrian thinks these methods should be in the Puddle model ie Puddle.add_entity, Puddle.remove_entity
  #because none of them use any information from this entity at all
 
	def add_entity_to_puddle(entity, puddle) # Michael
		unless puddleship_exists(entity, puddle)
			Puddleship.create(:entity_id => entity, :puddle_id => puddle)
		end
	end
	
	def remove_entity_from_puddle(entity, puddle) # Michael
		if puddleship_exists(entity, puddle)
			Puddleship.find_by_entity_id_and_puddle_id(entity, puddle).destroy
		end
	end
	
	def puddleship_exists(entity, puddle) # Michael, Adrian
		return Puddleship.find_by_entity_id_and_puddle_id(entity, puddle).nil? == false
	end
	

	
	#---------------------------------------- these methods are for manipulating popsicles related to this entity	
	
	def create_public_message(message,location) #Created by Adrian
		PublicPopsicle.create(:public_author_id => self.id, :content => message, :created_location_id => location)
	end
	
	def create_private_message(recipient_id, subject, message) #Adrian / Michael
		ReceiveMessage.create(:entity_id => recipient_id, 
							  :popsicle_id => PrivatePopsicle.create(:private_author_id => self.id, :content => message, :subject => subject).id)
	end
	
	# note we should be able to use the private_messages relationship defined above 
	# but currently this results in entities recieving any messages they send
	def get_private_messages #Michael
		messages = []
		ReceiveMessage.find_all_by_entity_id(self.id).each do |r|
			Popsicle.find_all_by_id(r.popsicle_id).each do |p|
				messages << p
			end
		end
		return messages
	end
	
	def new_messages #Michael
		pops = []
		ReceiveMessage.all.each do |r|
			if r.entity_id == self.id
				p = Popsicle.find(r.popsicle_id)
				if p.created_at == p.updated_at
					pops << p
				end
			end
		end
		return pops
	end
	
	#check it, vs note above
	def get_sent_messages #Michael
		messages = []
		Popsicle.find_all_by_private_author_id(self.id).each do |p|
			messages << p
		end
		return messages
	end
	
	#----------------------------------FRIENDSHIP METHODS-------------------------------------------------
	def is_friends_with(friend_id) # - Grace
		#friends = find_friends
		
		self.friends.each do |f|
			if f.id == friend_id
				return true
			end
		end

		groups = find_groups

		groups.each do |g|
			if g.id == friend_id
				return true
			end
		end
		
		return false		
	end
	
	def is_friend_of_friend(friend) # Created by Adrian
		#friends = find_friends
		
		self.friends.each do |f|
			if f.friends.include?friend
				return true
			end
		end
		
		return false
	end
	
	def has_friend_requested(friend_id) # - Grace
		requested = friend_requests_made
		
		if Friendship.find_by_entity_id_and_friend_id_and_accepted(self.id, friend_id, false).nil?
			return false
		else
			return true
		end
		
	end
	
	def friend_requests_made # - Grace	
		return Friendship.find_all_by_entity_id_and_accepted(self.id, false)	
	end
	
	def friend_request_received(entity_id) # - Grace	
		if Friendship.find_by_entity_id_and_friend_id_and_accepted(entity_id, self.id, false).nil?
			return false			
		else
			return true
		end	
	end
	
	def request_friend(friend_id) # - GRACE, edited by Adrian - privacy
    friend = Entity.find(friend_id)  
    if friend.can_be_sent_friend_request(self) 
		  Friendship.create(:entity_id => self.id, :friend_id => friend_id, :accepted => false)
		else
      return false
    end
	end
	
	#Add method to remove friends
	
	#Add method for quick access to friendship row (find_friendships)
	
	def friend_requests_received	
		Friendship.find_all_by_friend_id_and_accepted(self.id, false)	
	end
	
	def accept_friend_request(id)
		@request = Friendship.find_by_entity_id_and_friend_id(id, self.id)
		if !@request.nil?
			@request.accept_request
			return true
		else
			return false
		end
	end
	
	def deny_friend_request(id)
		@request = Friendship.find_by_entity_id_and_friend_id(id, self.id)
		if !@request.nil?
			@request.deny_request
			return true
		else
			return false
		end
	end
	
	def block_friend_request(id)
		@request = Friendship.find_by_entity_id_and_friend_id(id, self.id)
		if !@request.nil?
			@request.block_request
			return true
		else
			return false
		end
  end

end
